package mymail.cryptography.signature;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.spec.X509EncodedKeySpec;

import mymail.cryptography.asymmetric.RSA;

public class SignatureRSA {

	public static void main(String args[]) throws Exception {

		// 1. Ky du lieu chua ma hoa hoac duoc ma hoa bang Symmetric

		// Send mail
		// Ky
		// Ham nay se luu chu ky va public key
		SignatureRSA.signNonEncryptedData("data", "duong dan chu ky",
				"duong dan public key");

		// Receive mail
		// Xac nhan chu ky
		boolean result1 = SignatureRSA.verify("data", "duong dan chu ky",
				"duong dan public key");

		if (result1) {
			// Hien du lieu ra man hinh
		} else {
			// Hien khung chu ky khong dung
		}

		// ---------------------------------------

		// 2. Ky tap tin chua ma hoa hoac duoc ma hoa bang Symmetric

		// Send mail
		// Ky
		// Ham nay se luu chu ky va public key
		SignatureRSA.signNonEncryptedFile("duong dan file", "duong dan chu ky",
				"duong dan public key");

		// Receive mail
		// Xac nhan chu ky
		boolean result2 = SignatureRSA.verifyFile("duong dan file",
				"duong dan chu ky", "duong dan public key");

		if (result2) {
			// Cho nguoi dung xu ly tap tin
		} else {
			// Hien khung chu ky khong dung
		}

		// ---------------------------------------

		// 3. Ky du lieu da ma hoa

		// Send mail

		// Ma hoa
		RSA rsa1 = new RSA();

		String text = rsa1.Encrypt("data");

		// Luu privateKey

		FileOutputStream fos1 = new FileOutputStream("duong dan file private");
		fos1.write(rsa1.getPrivateKey().getEncoded());
		fos1.close();

		// Chen code Zip privateKey

		// Luu publicKey
		fos1 = new FileOutputStream("duong dan file public");
		fos1.write(rsa1.getPublicKey().getEncoded());
		fos1.close();

		// Ky
		SignatureRSA.signEncryptedData(text, "duong dan file chu ky",
				(PrivateKey) rsa1.getPrivateKey(),
				(PublicKey) rsa1.getPublicKey());

		// Receive mail
		// Xac nhan chu ky
		boolean result3 = SignatureRSA.verify("data", "duong dan chu ky",
				"duong dan public key");

		if (result3) {
			// Hien du lieu ra man hinh
			// Giai ma
			// Chen code giai ma vao
		} else {
			// Hien khung chu ky khong dung
		}

		// ---------------------------------------

		// 4. Ky tap tin da ma hoa

		// Send mail
		// Ma hoa
		RSA rsa2 = new RSA();

		String filename = rsa2.EncryptFile("duong dan file");

		SignatureRSA.signEncryptedFile(filename, "duong dan chu ky",
				(PrivateKey) rsa1.getPrivateKey(),
				(PublicKey) rsa1.getPublicKey());

		// Luu privateKey

		FileOutputStream fos2 = new FileOutputStream("duong dan file private");
		fos2.write(rsa1.getPrivateKey().getEncoded());
		fos2.close();

		// Chen code Zip privateKey

		// Luu publicKey
		fos2 = new FileOutputStream("duong dan file public");
		fos2.write(rsa1.getPublicKey().getEncoded());
		fos2.close();

		// Receive mail
		// Xac nhan chu ky
		boolean result4 = SignatureRSA.verifyFile("data", "duong dan chu ky",
				"duong dan public key");

		if (result4) {
			// Giai ma
			// Cho nguoi dung xu ly tap tin
		} else {
			// Hien khung chu ky khong dung
		}
	}

	public static void signEncryptedData(String data, String sigFilename,
			PrivateKey priv, PublicKey pub) throws Exception {

		// KeyPairGenerator keyGen = KeyPairGenerator.getInstance("DSA", "SUN");
		//
		// SecureRandom random = SecureRandom.getInstance("SHA1PRNG", "SUN");
		// keyGen.initialize(1024, random);
		//
		// KeyPair pair = keyGen.generateKeyPair();
		// PrivateKey priv = pair.getPrivate();
		// PublicKey pub = pair.getPublic();

		Signature rsa = Signature.getInstance("SHA1withRSA");

		rsa.initSign(priv);

		byte[] buffer = data.getBytes("utf-8");
		rsa.update(buffer, 0, buffer.length);

		byte[] realSig = rsa.sign();

		// File directory = new File(".");
		/* save the signature in a file */
		FileOutputStream sigfos = new FileOutputStream(sigFilename);
		sigfos.write(realSig);
		sigfos.close();

		/* save the public key in a file */
		// byte[] key = pub.getEncoded();
		// FileOutputStream keyfos = new FileOutputStream(
		// directory.getCanonicalPath() + "/signatures/" + publicFilename);
		// keyfos.write(key);
		// keyfos.close();
	}

	public static void signEncryptedFile(String dataFilename,
			String sigFilename, PrivateKey priv, PublicKey pub)
			throws Exception {

		// KeyPairGenerator keyGen = KeyPairGenerator.getInstance("DSA", "SUN");
		//
		// SecureRandom random = SecureRandom.getInstance("SHA1PRNG", "SUN");
		// keyGen.initialize(1024, random);
		//
		// KeyPair pair = keyGen.generateKeyPair();
		// PrivateKey priv = pair.getPrivate();
		// PublicKey pub = pair.getPublic();

		Signature rsa = Signature.getInstance("SHA1withRSA");

		rsa.initSign(priv);

		FileInputStream fis = new FileInputStream(dataFilename);
		BufferedInputStream bufin = new BufferedInputStream(fis);
		byte[] buffer = new byte[1024];
		int len;
		while ((len = bufin.read(buffer)) >= 0) {
			rsa.update(buffer, 0, len);
		}
		;
		bufin.close();

		byte[] realSig = rsa.sign();

		// File directory = new File(".");
		/* save the signature in a file */
		FileOutputStream sigfos = new FileOutputStream(sigFilename);
		sigfos.write(realSig);
		sigfos.close();

		/* save the public key in a file */
		// byte[] key = pub.getEncoded();
		// FileOutputStream keyfos = new FileOutputStream(
		// directory.getCanonicalPath() + "/signatures/" + publicFilename);
		// keyfos.write(key);
		// keyfos.close();
	}

	public static void signNonEncryptedData(String data, String sigFilename,
			String publicFilename) throws Exception {

		KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");

		// SecureRandom random = SecureRandom.getInstance("SHA1PRNG", "SUN");
		keyGen.initialize(1024);

		KeyPair pair = keyGen.generateKeyPair();
		PrivateKey priv = pair.getPrivate();
		PublicKey pub = pair.getPublic();

		Signature rsa = Signature.getInstance("SHA1withRSA");

		rsa.initSign(priv);

		byte[] buffer = data.getBytes("utf-8");
		rsa.update(buffer, 0, buffer.length);

		byte[] realSig = rsa.sign();

		File directory = new File(".");
		/* save the signature in a file */
		FileOutputStream sigfos = new FileOutputStream(sigFilename);
		sigfos.write(realSig);
		sigfos.close();

		/* save the public key in a file */
		byte[] key = pub.getEncoded();
		FileOutputStream keyfos = new FileOutputStream(publicFilename);
				//directory.getCanonicalPath() + "/signatures/" + publicFilename);
		keyfos.write(key);
		keyfos.close();
	}

	public static void signNonEncryptedFile(String dataFilename,
			String sigFilename, String publicFilename) throws Exception {

		KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");

		// SecureRandom random = SecureRandom.getInstance("SHA1PRNG", "SUN");
		keyGen.initialize(1024);

		KeyPair pair = keyGen.generateKeyPair();
		PrivateKey priv = pair.getPrivate();
		PublicKey pub = pair.getPublic();

		Signature rsa = Signature.getInstance("SHA1withRSA");

		rsa.initSign(priv);

		FileInputStream fis = new FileInputStream(dataFilename);
		BufferedInputStream bufin = new BufferedInputStream(fis);
		byte[] buffer = new byte[1024];
		int len;
		while ((len = bufin.read(buffer)) >= 0) {
			rsa.update(buffer, 0, len);
		}
		;
		bufin.close();

		byte[] realSig = rsa.sign();

		// File directory = new File(".");
		/* save the signature in a file */
		FileOutputStream sigfos = new FileOutputStream(sigFilename);
		sigfos.write(realSig);
		sigfos.close();

		/* save the public key in a file */
		byte[] key = pub.getEncoded();
		FileOutputStream keyfos = new FileOutputStream(publicFilename);
		keyfos.write(key);
		keyfos.close();
	}

	public static boolean verify(String data, String sigFilename,
			String publicFilename) throws Exception {

		FileInputStream keyfis = new FileInputStream(publicFilename);
		byte[] encKey = new byte[keyfis.available()];
		keyfis.read(encKey);

		keyfis.close();

		X509EncodedKeySpec pubKeySpec = new X509EncodedKeySpec(encKey);

		KeyFactory keyFactory = KeyFactory.getInstance("RSA");

		PublicKey pubKey = keyFactory.generatePublic(pubKeySpec);

		FileInputStream sigfis = new FileInputStream(sigFilename);
		byte[] sigToVerify = new byte[sigfis.available()];
		sigfis.read(sigToVerify);
		sigfis.close();

		Signature sig = Signature.getInstance("SHA1withRSA");

		sig.initVerify(pubKey);

		byte[] buffer = data.getBytes("utf-8");
		sig.update(buffer, 0, buffer.length);

		boolean verifies = sig.verify(sigToVerify);

		return verifies;
	}

	public static boolean verifyFile(String dataFilename, String sigFilename,
			String publicFilename) throws Exception {

		FileInputStream keyfis = new FileInputStream(publicFilename);
		byte[] encKey = new byte[keyfis.available()];
		keyfis.read(encKey);

		keyfis.close();

		X509EncodedKeySpec pubKeySpec = new X509EncodedKeySpec(encKey);

		KeyFactory keyFactory = KeyFactory.getInstance("RSA");

		PublicKey pubKey = keyFactory.generatePublic(pubKeySpec);

		FileInputStream sigfis = new FileInputStream(sigFilename);
		byte[] sigToVerify = new byte[sigfis.available()];
		sigfis.read(sigToVerify);
		sigfis.close();

		Signature sig = Signature.getInstance("SHA1withRSA");

		sig.initVerify(pubKey);

		FileInputStream datafis = new FileInputStream(dataFilename);
		BufferedInputStream bufin = new BufferedInputStream(datafis);

		byte[] buffer = new byte[1024];
		int len;
		while (bufin.available() != 0) {
			len = bufin.read(buffer);
			sig.update(buffer, 0, len);
		}
		;

		boolean verifies = sig.verify(sigToVerify);

		return verifies;
	}
}
